import { GameState, ScoketServer, SocketType } from "../Http/SocketServer";
import GlobDef from "../Module/GlobDef";

interface PlayerInfo {
    name: string,
    roomid: number,
    createRoom: number,
    conn: any,
    userid: number,
    nConTime: number,
    nScore: number,
    state: number //playerStart
}

enum playerStart {
    goin,    //在房间内
    ready,   //准备
    ingame,  //游戏中
    end      //结算了
}

export class GameServer {


    public static Instance: GameServer = null;
    public static GetInst(): GameServer {

        if (!GameServer.Instance) {
            GameServer.Instance = new GameServer()
        }
        return GameServer.Instance;
    }


    public m_pPlayerData = {}
    public m_pRoomToPlayerlist = {};
    public m_pRoomHolder = {};
    public m_pbaseId = 10000;
    public m_nConTime = 80;

    /**
     * 用户注册名
     */
    public setgameinfo(conn, msg) {

        let _Player: PlayerInfo = {
            name: "",
            roomid: 0,
            conn: null,
            userid: 0,
            nConTime: 0,
            nScore: 0,
            createRoom: 0,
            state: 0
        }
        let roomid = GlobDef.GetRandom(100000, 1000000);
        let userid = this.m_pbaseId++;

        _Player.nConTime = this.m_nConTime;
        _Player.conn = conn;
        _Player.name = msg.name;
        _Player.roomid = roomid;
        _Player.userid = userid;
        _Player.createRoom = roomid;
        _Player.state = playerStart.ready;
        this.m_pPlayerData[userid] = _Player;
        this.m_pRoomToPlayerlist[roomid] = {};
        this.m_pRoomToPlayerlist[roomid][userid] = _Player;
        this.m_pRoomHolder[roomid] = userid;

        let pNameByUid = {}
        pNameByUid[userid] = msg.name;
        let _data = { roomid: roomid, name: pNameByUid, userid: userid }
        ScoketServer.Instance.onSend(conn, _data, SocketType.setName);
    }


    /**
     * 加入其他房间 (只能是当前房间只有本人);
     * @param conn 
     * @param msg 
     */
    public joinOtherRoom(conn, msg) {
        let roomid: number = msg.roomid;
        let userid: number = msg.userid;

        let roomid_arr = Object.keys(this.m_pRoomToPlayerlist);
        if (roomid_arr.indexOf(roomid.toString()) === -1) {
            return ScoketServer.Instance.OnError(conn, '不存在此房间');
        };

        if (this.m_pRoomHolder[roomid] == userid) {
            return ScoketServer.Instance.OnError(conn, '不能加入自己的房间')
        }

        //判断是否是空的房间，空的房间只能是房间的主人才能使用
        let playerList = this.m_pRoomToPlayerlist[roomid];
        let coutVal = 0
        for (const key in playerList) {
            if (isNaN(Number(key))) continue;
            coutVal++;
        }
        if (coutVal == 0) {
            return ScoketServer.Instance.OnError(conn, '无法加入此房间');
        }

        //判断要加入的房间是否已经开始游戏了
        let boo_str = this.m_pRoomToPlayerlist[roomid]['gamestate'];
        if (boo_str != undefined && boo_str == GameState.start) {
            return ScoketServer.Instance.OnError(conn, '房间已开始');
        }

        this.UpRoom(userid, roomid, true);
    }

    /**
     * 返回自己的房间
     */
    public ReturnSelfRoom(conn, msg) {

        let userid = msg.userid;
        let _playerInfo = this.m_pPlayerData[userid];
        let selfRoom = _playerInfo.createRoom;
        this.UpRoom(userid, selfRoom, false);
    }

    /**
     * 准备游戏
     */
    public ReadGame(conn, msg) {
        let userid = msg.userid;
        let _playerInfo = this.m_pPlayerData[userid];
        _playerInfo.state = playerStart.ready;
        let roomid = _playerInfo.roomid;
        let _playerList = this.m_pRoomToPlayerlist[roomid]
        let readyName = {};

        let readConn: any[] = [];
        for (const key in _playerList) {
            if (isNaN(parseInt(key))) continue;
            let _player = _playerList[key];
            if (_player.state !== playerStart.ready) continue;
            readyName[_player.userid] = _player.name;

            readConn.push(_player.conn);
        }

        readConn.forEach(_Conn => {
            let _data = { roomid: roomid, name: readyName, masterid: this.m_pRoomHolder[roomid] };
            ScoketServer.Instance.onSend(_Conn, _data, SocketType.readyGame);
        });
    }

    public UpRoom(_userid: number, _roomid: number, joinOther: boolean = false) {

        let lastRoomid = this.m_pPlayerData[_userid].roomid;
        this.m_pPlayerData[_userid].roomid = _roomid;

        //先除去原来房间的player
        let last_arr = this.m_pRoomToPlayerlist[lastRoomid];
        delete last_arr[_userid];

        //再添加到新的房间去
        this.m_pRoomToPlayerlist[_roomid][_userid] = this.m_pPlayerData[_userid];
        let self = this;
        let TempFun = function (roomidTp: number, socketTp: SocketType) {
            let nameObj = {};
            let vconn = [];
            let roomToPlayerObj = self.m_pRoomToPlayerlist[roomidTp];
            console.log(roomToPlayerObj);
            for (const key in roomToPlayerObj) {
                if (isNaN(parseInt(key))) continue;
                let _player = roomToPlayerObj[key];
                nameObj[_player.userid] = _player.name;
                vconn.push(_player.conn);
            }
            vconn.forEach(_conn => {
                let _data = { roomid: roomidTp, name: nameObj, masterid: self.m_pRoomHolder[roomidTp] };
                ScoketServer.Instance.onSend(_conn, _data, socketTp);
            });
        }

        //若加入别人的房间： 则在加入的房间广播
        if (joinOther === true) {
            TempFun(_roomid, SocketType.joinRoom);
        }
        //若返回自己的房间： 则两个房间都需要广播
        else {
            TempFun(_roomid, SocketType.ReturnSelfRoom);
            TempFun(lastRoomid, SocketType.ReturnSelfRoom);
        }
    }

    /**
     * 申请主持游戏
     */
    public ReqHostMethod(conn, msg) {

        let roomid = msg.roomid;
        let userid = msg.userid;

        let hostUserid = this.m_pRoomToPlayerlist[roomid]['hostUserid'];
        if (hostUserid) {
            ScoketServer.Instance.OnError(conn, '不符合游戏逻辑');
            return;
        }

        this.m_pRoomToPlayerlist[roomid]['hostUserid'] = userid;

        //需要广播到这个房间里面的玩家
        let roomToPlayerObj = this.m_pRoomToPlayerlist[roomid];

        for (const key2 in roomToPlayerObj) {

            if (isNaN(Number(key2))) continue;
            let _player = roomToPlayerObj[key2];
            let _data = { hostUserid: userid }
            ScoketServer.Instance.onSend(_player.conn, _data, SocketType.reqHost);
        }
    }


    /**
     * 设置答案
     */
    public DJsFun = null;
    public setResule(conn, msg) {

        let resuleTxt = msg.resule;
        let roomid = msg.roomid;

        let Answer = this.m_pRoomToPlayerlist[roomid]['Answer'];
        if (Answer) {
            return ScoketServer.Instance.OnError(conn, '不符合游戏逻辑');
        };
        this.m_pRoomToPlayerlist[roomid]['Answer'] = resuleTxt;

        //需要广播到这个房间里面的玩家
        let roomToPlayerObj = this.m_pRoomToPlayerlist[roomid];
        for (const key2 in roomToPlayerObj) {

            if (isNaN(Number(key2))) continue;
            let _player = roomToPlayerObj[key2];
            let _data = { startgame: true, gametime: 80 };
            _player.state = playerStart.ingame,
                ScoketServer.Instance.onSend(_player.conn, _data, SocketType.wirteResule);
        }

        this.m_pRoomToPlayerlist[roomid]['StartGameTime'] = GlobDef.GetTimeSec();
        this.m_pRoomToPlayerlist[roomid]['gamestate'] = GameState.start;
        this.DJsFun = setTimeout(() => {
            this.GameEnd(roomToPlayerObj);
        }, 80000, this);
    }


    /**
     * 进行绘画
     */

    public onDrow(conn, msg) {
        let roomid = msg.roomid;

        //直接广播
        let roomToPlayerObj = this.m_pRoomToPlayerlist[roomid];
        for (const key2 in roomToPlayerObj) {

            if (isNaN(Number(key2))) continue;
            let _player = roomToPlayerObj[key2];

            let _data = { x: msg.x, y: msg.y, type: msg.type };
            ScoketServer.Instance.onSend(_player.conn, _data, SocketType.game);
        }

    }


    /**
     * 其他玩家发送答案验证
     */
    public onUserResuleReq(conn, msg) {

        let roomid = msg.roomid;
        let userid = msg.userid;
        let text = msg.text;

        let Answer = this.m_pRoomToPlayerlist[roomid]['Answer'];
        if (Answer !== text) {
            return ScoketServer.Instance.OnError(conn, '回答错误')
        }

        //回答正确后房间内广播
        let roomToPlayerObj = this.m_pRoomToPlayerlist[roomid];
        for (const key2 in roomToPlayerObj) {

            if (isNaN(Number(key2))) continue;
            let _player = roomToPlayerObj[key2];

            let _data = { success: true, userid: userid };
            ScoketServer.Instance.onSend(_player.conn, _data, SocketType.sendResule);
        }

        //设置耗时、分数]
        let conTime = GlobDef.GetTimeSec() - roomToPlayerObj['StartGameTime'];
        this.m_pPlayerData[userid].nConTime = conTime;
        this.m_pPlayerData[userid].nScore = 1;
        this.checkPlayerRes(roomToPlayerObj);
    }

    public checkPlayerRes(roomToPlayerObj) {

        let count = 0;
        let HostId = roomToPlayerObj.hostUserid;
        for (const key in roomToPlayerObj) {

            if (isNaN(Number(key)) || Number(key) == HostId) continue;

            let _player = roomToPlayerObj[key];
            let res = _player['nScore'];

            if (!res) {
                count++;
            }
        }
        if (count == 0) {
            this.GameEnd(roomToPlayerObj);
            if (this.DJsFun) clearTimeout(this.DJsFun);
        }
    }

    /**
     * 游戏结束
     * @param roomToPlayerObj 这个房间里面的人
     */
    public GameEnd(roomToPlayerObj) {

        let conn = [];
        let vNewPlayerObj = [];

        let gameend = roomToPlayerObj['gamestate'];
        if (gameend !== undefined && gameend == GameState.end) return;

        roomToPlayerObj['gamestate'] = GameState.end;
        let hostUserid = roomToPlayerObj['hostUserid'];
        for (const key in roomToPlayerObj) {

            if (isNaN(Number(key))) continue;
            let _player = roomToPlayerObj[key];

            let obj = {
                userid: _player['userid'],
                name: _player['name'],
                nScore: _player['nScore'],
                nConTime: _player['nConTime']
            }
            _player.state = playerStart.end,
                conn.push(_player.conn);
            if (Number(key) !== hostUserid) {
                vNewPlayerObj.push(obj);
            }

            _player['nScore'] = 0;
            _player['nConTime'] = 0;
        }

        vNewPlayerObj.sort((a, b) => {
            return a.nScore - b.nScore;
        })

        conn.forEach(list => {

            ScoketServer.Instance.onSend(list, vNewPlayerObj, SocketType.GameEnd);
        });
        roomToPlayerObj['hostUserid'] = 0; //重置
        roomToPlayerObj['Answer'] = '';
        roomToPlayerObj['StartGameTime'] = 0;

    }
}

